home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / gcc / ixemlsrc.lha / ixemul / library / stackextend.c < prev    next >
C/C++ Source or Header  |  1996-03-13  |  9KB  |  348 lines

  1. #define    KERNEL
  2. #include "ixemul.h"
  3.  
  4. #include <exec/memory.h>
  5. #include <signal.h>
  6. #include <unistd.h>
  7.  
  8. /*
  9.  * Glue asm to C.
  10.  */
  11. asm("
  12.     .globl    ___stkext
  13. ___stkext:
  14.     moveml    d0/d1/a0/a1/a6,sp@-
  15.     subqw    #4,sp        | sigset_t
  16.     jbsr    _atomic_on
  17.     subw    #12,sp        | struct StackSwapStruct
  18.     jbsr    _stkext
  19.     movel    4:W,a6
  20.     movel    sp,a0
  21.     jsr    a6@(-0x2dc)    | StackSwap(a0)
  22.     jbsr    _atomic_off
  23.     addqw    #4,sp        | StackSwapStruct is not copied
  24.     moveml    sp@+,d0/d1/a0/a1/a6
  25.     rts
  26.  
  27.     .globl    ___stkext_f    | see above
  28. ___stkext_f:
  29.     moveml    d0/d1/a0/a1/a6,sp@-
  30.     subqw    #4,sp
  31.     jbsr    _atomic_on
  32.     subw    #12,sp
  33.     jbsr    _stkext_f
  34.     movel    4:W,a6
  35.     movel    sp,a0
  36.     jsr    a6@(-0x2dc)
  37.     jbsr    _atomic_off
  38.     addqw    #4,sp
  39.     moveml    sp@+,d0/d1/a0/a1/a6
  40.       rts
  41.   
  42.     .globl    ___stkrst_f    | see above
  43. ___stkrst_f:
  44.     moveml    d0/d1/a0/a1/a6,sp@-
  45.     subqw    #4,sp
  46.     jbsr    _atomic_on
  47.     subw    #12,sp
  48.     jbsr    _stkrst_f
  49.     movel    4:W,a6
  50.     movel    sp,a0
  51.     jsr    a6@(-0x2dc)
  52.     jbsr    _atomic_off
  53.     addqw    #4,sp
  54.     moveml    sp@+,d0/d1/a0/a1/a6
  55.       rts
  56.   
  57.     .globl    ___stkrst
  58. ___stkrst:
  59.     moveml    d0/d1/a0/a1/a6,sp@-        | preserve registers
  60.     subqw    #4,sp        | make room for the signal mask
  61.     jbsr    _atomic_on    | disable all signals
  62.     subw    #12,sp        | make room for a StackSwapStruct
  63.     jbsr    _stkrst        | calculate either target sp or StackSwapStruct
  64.     tstl    d0        | set target sp?
  65.     jeq    swpfrm        | jump if not
  66.     movel    d0,a0        | I have a lot of preserved registers and
  67.                 | returnadresses on the stack. It's necessary
  68.                 | to copy them to the new location
  69.     moveq    #6,d0        | 1 rts, 5 regs and 1 signal mask to copy (2+5+1)-1=7
  70.     leal    sp@(40:W),a1    | get address of uppermost byte+1 (1+5+1)*4+12=40
  71.     cmpl    a0,a1        | compare with target location
  72.     jls    lp1        | jump if source<=target
  73.     leal    a0@(-28:W),a0    | else start at lower bound (1+5+1)*4=28
  74.     leal    a1@(-28:W),a1
  75.     movel    a0,sp        | set sp to reserve the room
  76. lp0:    movel    a1@+,a0@+    | copy with raising addresses
  77.     dbra    d0,lp0        | as long as d0>=0.
  78.     jra    endlp        | ready
  79. lp1:    movel    a1@-,a0@-    | copy with falling addresses
  80.     dbra    d0,lp1        | as long as d0>=0
  81.     movel    a0,sp        | finally set sp
  82.     jra    endlp        | ready
  83. swpfrm:    movel    4:W,a6        | If sp wasn't set call StackSwap()
  84.     movel    sp,a0
  85.     jsr    a6@(-0x2dc)
  86. endlp:    jbsr    _atomic_off    | reenable signals
  87.     addqw    #4,sp        | adjust sp
  88.     moveml    sp@+,d0/d1/a0/a1/a6        | restore registers
  89.     rts            | and return
  90. ");
  91.  
  92. void __stkrst_f(void);
  93.  
  94. #define    STK_UPPER    \
  95. (u.u_stk_used != NULL ? u.u_stk_used->upper : u.u_org_upper)
  96.  
  97. #define    STK_LOWER    \
  98. (u.u_stk_used != NULL ? (void *)(u.u_stk_used + 1) : u.u_org_lower)
  99.  
  100. #define    stk_safezone    6144    /* into ixprefs? */
  101. #define    stk_minframe    32768
  102.  
  103. void initstack(void)
  104. {
  105.   struct Process *me;
  106.   APTR lower, upper;
  107.  
  108.   me = (struct Process *)SysBase->ThisTask;
  109.  
  110.   u.u_tc_splower = me->pr_Task.tc_SPLower;
  111.   u.u_tc_spupper = me->pr_Task.tc_SPUpper;
  112.  
  113.   if (me->pr_CLI)
  114.   {
  115.     /* Process stackframe:
  116.      * me->pr_ReturnAddr points to size of stack (ULONG)
  117.      *         +4                  returnaddress
  118.      *         +8                  stackframe
  119.      */
  120.     lower = (char *)me->pr_ReturnAddr + 8 - *(ULONG *)me->pr_ReturnAddr;
  121.     upper = (char *)me->pr_ReturnAddr + 8;
  122.   }
  123.   else
  124.   {
  125.     lower = u.u_tc_splower;
  126.     upper = u.u_tc_spupper;
  127.   }
  128.  
  129.   u.u_org_lower = lower; /* Lower stack bound */
  130.   u.u_org_upper = upper; /* Upper stack bound +1 */
  131.   u.u_stk_used = NULL;   /* Stackframes in use */
  132.   u.u_stk_spare = NULL;  /* Spare stackframes */
  133.  
  134.   u.u_stk_limit = (void **)-1; /* Used uninitialized? Raise address error */
  135.   u.u_stk_argbt = 256; /* set some useful default */
  136. }
  137.  
  138. void __init_stk_limit(void **limit, unsigned long argbytes)
  139. {
  140.   u.u_stk_limit = limit;
  141.   u.u_stk_argbt = argbytes;
  142.   *limit = (char *)u.u_org_lower + stk_safezone + argbytes;
  143. }
  144.  
  145. /*
  146.  * Free all spare stackframes
  147.  */
  148. void freestack(void)
  149. {
  150.   struct stackframe *sf, *s2;
  151.  
  152.   sf = u.u_stk_spare;
  153.   u.u_stk_spare = NULL;
  154.   while (sf != NULL)
  155.   {
  156.     s2 = sf->next;
  157.     FreeMem(sf, (char *)sf->upper - (char *)sf);
  158.     sf = s2;
  159.   }
  160. }
  161.  
  162. void __stkovf(void)
  163. {
  164.   u.u_stk_limit = NULL; /* disable stackextend from now on */
  165.   for (;;)
  166.     kill(getpid(), SIGSEGV); /* Ciao */
  167. }
  168.  
  169. /*
  170.  * Signal routines may want to benefit from stackextension too -
  171.  * so make all the stack handling functions atomic.
  172.  * FIXME: This seems to have the potential to break a Forbid() ?!?
  173.  */
  174. void atomic_on(sigset_t old)
  175. {
  176.   sigset_t fill;
  177.   sigfillset(&fill);
  178.   sigprocmask(SIG_SETMASK, &fill, &old);
  179. }
  180.  
  181. void atomic_off(sigset_t old)
  182. {
  183.   sigprocmask(SIG_SETMASK, &old, NULL);
  184. }
  185.  
  186. /*
  187.  * Move a stackframe with a minimum of requiredstack bytes to the used list
  188.  * and fill the StackSwapStruct structure.
  189.  */
  190. static void pushframe(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old)
  191. {
  192.   struct stackframe *sf;
  193.  
  194.   requiredstack += stk_safezone + u.u_stk_argbt;
  195.   if (requiredstack < stk_minframe)
  196.     requiredstack = stk_minframe;
  197.  
  198.   for (;;)  
  199.   {
  200.     sf = u.u_stk_spare; /* get a stackframe from the spares list */
  201.     if (sf == NULL)
  202.     { /* stack overflown */
  203.       sf = AllocMem(requiredstack + sizeof(struct stackframe), MEMF_PUBLIC);
  204.       if (sf == NULL)
  205.       { /* and we have no way to extend it :-| */
  206.         sigprocmask(SIG_SETMASK, old, NULL);
  207.         __stkovf();
  208.       }
  209.       sf->upper = (char *)(sf + 1) + requiredstack;
  210.       break;
  211.     }
  212.     u.u_stk_spare = sf->next;
  213.     if ((char *)sf->upper - (char *)(sf + 1) >= requiredstack)
  214.       break;
  215.     FreeMem(sf, (char *)sf->upper - (char *)sf);
  216.   }
  217.  
  218.   /* Add stackframe to the used list */
  219.   sf->next = u.u_stk_used;
  220.   u.u_stk_used = sf;
  221.   *u.u_stk_limit = (char *)(sf + 1) + stk_safezone + u.u_stk_argbt;
  222.  
  223.   /* prepare StackSwapStruct */
  224.   sss->stk_Pointer = sf->upper;
  225.   sss->stk_Lower = sf + 1;
  226.   sss->stk_Upper = (ULONG)sf->upper;
  227. }
  228.  
  229. /*
  230.  * Allocate a new stackframe with d0 bytes minimum.
  231.  */
  232. void stkext(struct StackSwapStruct sss, sigset_t old,
  233.  long d0, long d1, long a0, long a1, long a6, long ret1)
  234. {
  235.   void *callsp = &ret1 + 1;
  236.   int cpsize = (char *)callsp - (char *)&old;
  237.  
  238.   if (callsp >= STK_UPPER || callsp < STK_LOWER)
  239.     return; /* User intentionally left area of stackextension */
  240.  
  241.   pushframe(d0, &sss, &old);
  242.   *(char **)&sss.stk_Pointer -= cpsize;
  243.   CopyMem(&old, sss.stk_Pointer, cpsize);
  244. }
  245.  
  246. /*
  247.  * Allocate a new stackframe with d0 bytes minimum, copy the callers arguments
  248.  * and set his returnaddress (offset d1 from the sp when called) to stk_rst_f
  249.  */
  250. void stkext_f(struct StackSwapStruct sss, sigset_t old,
  251.  long d0, long d1, long a0, long a1, long a6, long ret1)
  252. {
  253.   void *argtop, *callsp = &ret1 + 1;
  254.   int cpsize;
  255.  
  256.   if (callsp >= STK_UPPER || callsp < STK_LOWER)
  257.     return; /* User intentionally left area of stackextension */
  258.  
  259.   argtop = (char *)callsp + u.u_stk_argbt;    /* Top of area with arguments */
  260.   if (argtop > STK_UPPER)
  261.     argtop = STK_UPPER;
  262.   cpsize = (char *)argtop - (char *)&old;
  263.  
  264.   pushframe(d0 + u.u_stk_argbt, &sss, &old);
  265.   *(char **)&sss.stk_Pointer -= cpsize;
  266.   CopyMem(&old,sss.stk_Pointer, cpsize);
  267.   u.u_stk_used->savesp = (char *)callsp + d1; /* store sp */
  268.   *(void **)((char *)sss.stk_Upper - ((char *)argtop - (char *)callsp) + d1)
  269.     = &__stkrst_f; /* set returnaddress */
  270. }
  271.  
  272. /*
  273.  * Move all used stackframes upto (and including) sf to the spares list
  274.  * and fill the StackSwapStruct structure.
  275.  */
  276. static void popframes(struct stackframe *sf, struct StackSwapStruct *sss)
  277. {
  278.   struct stackframe *sf2;
  279.  
  280.   if (sf->next != NULL)
  281.   {
  282.     sss->stk_Lower = sf->next + 1;
  283.     sss->stk_Upper = (ULONG)sf->next->upper;
  284.     *u.u_stk_limit = (char *)(sf->next + 1) + stk_safezone + u.u_stk_argbt;
  285.   }
  286.   else
  287.   {
  288.     sss->stk_Lower = u.u_tc_splower;
  289.     sss->stk_Upper = (ULONG)u.u_tc_spupper;
  290.     *u.u_stk_limit = (char *)u.u_org_lower + stk_safezone + u.u_stk_argbt;
  291.   }
  292.   sf2 = u.u_stk_spare;
  293.   u.u_stk_spare = u.u_stk_used;
  294.   u.u_stk_used = sf->next;
  295.   sf->next = sf2;
  296. }
  297.  
  298. /*
  299.  * Set stackpointer back to some previous value
  300.  * != NULL: on the same stackframe (returns sp)
  301.  * == NULL: on another stackframe
  302.  */
  303. void *stkrst(struct StackSwapStruct sss, sigset_t old,
  304.  void *d0, long d1, long a0, long a1, long a6, long ret1)
  305. {
  306.   void *callsp = &ret1 + 1;
  307.   int cpsize = (char *)callsp - (char *)&old;
  308.   struct stackframe *sf1, *sf2;
  309.  
  310.   if (d0 >= STK_LOWER && d0 < STK_UPPER)
  311.     return d0;
  312.  
  313.   sf1 = u.u_stk_used;
  314.   if (sf1 == NULL)
  315.     return d0;
  316.   for (;;)
  317.   {
  318.     sf2 = sf1->next;
  319.     if (sf2 == NULL)
  320.     {
  321.       if (d0 < u.u_org_lower || d0 >= u.u_org_upper)
  322.         return d0;
  323.       break;
  324.     }
  325.     if (d0 >= (void *)(sf2 + 1) && d0 < sf2->upper) /* This stackframe fits */
  326.       break;
  327.     sf1 = sf2;
  328.   }
  329.   popframes(sf1, &sss);
  330.   sss.stk_Pointer = (char *)d0 - cpsize;
  331.   CopyMem(&old, sss.stk_Pointer,cpsize);
  332.   return NULL;
  333. }
  334.  
  335. /*
  336.  * return to last stackframe
  337.  */
  338. void stkrst_f(struct StackSwapStruct sss, sigset_t old,
  339.  long d0, long d1, long a0, long a1, long a6)
  340. {
  341.   void *callsp = &a6 + 1; /* This one has no returnaddress - it's a fallback for rts */
  342.   int cpsize = (char *)callsp - (char *)&old;
  343.  
  344.   sss.stk_Pointer = (char *)u.u_stk_used->savesp - cpsize;
  345.   popframes(u.u_stk_used, &sss);
  346.   CopyMem(&old, sss.stk_Pointer, cpsize);
  347. }
  348.